package wortubung.inflection;

import static wortubung.util.CommonUtils.*;

import wortubung.core.GENDER;
import wortubung.core.LANG;
import wortubung.util.MatrixPrinter;
import wortubung.util.TransliterateException;

public class DeclensionResult {
	private boolean  isGuessed;
	private String   usage;
	private String[] titles;
	private GENDER   gender;     // valid only for noun declension, for the single column.

	private String[] nominative;
	private String[] genitive;
	private String[] dative;
	private String[] accusative;

	public DeclensionResult(String usage, String[] titles) {
		this(usage, null, null, null, null, titles, false);
	}

	public DeclensionResult(String usage, String[] nom, String[] gen, String[] dat, String[] acc, String[] titles) {
		this(usage, nom, gen, dat, acc, titles, false);
	}

	public DeclensionResult(GENDER gender, String[] nom, String[] gen, String[] dat, String[] acc, String[] titles, boolean isGuessed) {
		this((String)null, nom, gen, dat, acc, titles, isGuessed);
		this.gender = gender;
		this.usage = (gender == null) ? "n." : ("n.-" + gender);
	}

	public DeclensionResult(String usage, String[] nom, String[] gen, String[] dat, String[] acc, String[] titles, boolean isGuessed) {
		this.usage = usage;
		this.nominative = nom;
		this.accusative = acc;
		this.dative = dat;
		this.genitive = gen;
		this.titles = titles;
		this.isGuessed = isGuessed;
	}

	public String[][] getResults(LANG lang) {
		return getResults(lang, false);
	}

	/**
	 * @return in the order of <code>DECLENSION.values(LANG.de)</code> when result is present.
	 */
	public String[][] getResults(LANG lang, boolean addDeclName) {
		DECLENSION[] decls = DECLENSION.values(lang);
		String[][] saa = new String[decls.length][];
		int idx = 0;
		String[] sa;
		for (DECLENSION decl : decls) {
			sa = get(decl);
			if (isNotEmpty(sa))
				saa[idx++] = addDeclName ? augment(decl.getDisplay(lang, false), sa) : sa;
		}
		return shrink(saa);
	}

	public int getLongestWordWidth(LANG lang) {
		int ret = 0;
		for (DECLENSION decl : DECLENSION.values(lang))
			ret = maxLen(ret, get(decl));
		return ret;
	}

	public DeclensionResult clone(boolean deep) {
		DeclensionResult ret = new DeclensionResult(usage, titles);
		ret.copyDeclensionResult(this, deep);
		return ret;
	}

	public void copyDeclensionResult(DeclensionResult other, boolean deep) {
		if (deep) {
			if (other.nominative != null)
				this.nominative = copyOf(other.nominative);
			if (other.genitive != null)
				this.genitive = copyOf(other.genitive);
			if (other.dative != null)
				this.dative = copyOf(other.dative);
			if (other.accusative != null)
				this.accusative = copyOf(other.accusative);
		} else {
			this.nominative = other.nominative;
			this.genitive = other.genitive;
			this.dative = other.dative;
			this.accusative = other.accusative;
		}
	}

	/**
	 * Replace "-" in the result strings with value.
	 * @throws TransliterateException 
	 */
	public void instantiateResult(String value, LANG lang) throws TransliterateException {
		String[][] results = getResults(lang, false);
		if (results == null)
			return;
		for (String[] sa : results) {
			for (int i=length(sa)-1; i>=0; --i) {
				if (sa[i] != null)
					sa[i] = sa[i].replaceAll("-", value);
			}
			lang.toVernacular(sa);
		}
	}

	public boolean isGuessed() { return isGuessed; }
	public GENDER getGender() { return gender; }
	public String getUsage() { return usage; }
	public String[] getNominative() { return nominative; }
	public String[] getGenitive() { return genitive; }
	public String[] getDative() { return dative; }
	public String[] getAccusative() { return accusative; }

	public String[] get(DECLENSION decl) {
		switch (decl) {
		case Nominative: return getNominative();
		case Genitive:   return getGenitive();
		case Dative:     return getDative();
		case Accusative: return getAccusative();
		default:         return null;
		}
	}

	public String[] getTitles(boolean withUsage) {
		if (titles == null || !withUsage)
			return titles;
		String[] ret = new String[titles.length + 1];
		for (int i=titles.length-1; i>=0; --i)
			ret[i+1] = titles[i];
		ret[0] = neverNull(usage);
		return ret;
	}

	public MatrixPrinter.Matrix toMatrix(LANG lang) {
		return new MatrixPrinter.Matrix(getTitles(true), getResults(lang, true));
	}

}
